/*
 * @(#)Solver.java    Jul 13, 2010
 *
 * Copyright 2009 Nyber Shanghai, Inc. All rights reserved.
 */

package com.lab.util.concurrent;

import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * CyclicBarrier: 一个同步辅助类, 它允许一组线程互相等待, 直到到达某个公共屏障点 (common barrier point). 
 * 在涉及一组固定大小的线程的程序中, 这些线程必须不时地互相等待, 
 * 此时CyclicBarrier 很有用. 因为该 barrier 在释放等待线程后可以重用, 所以称它为循环的 barrier.
 *
 * @author nickevin@gmail.com
 * @version Jul 13, 2010 1:49:10 PM
 */

public class CyclicBarrierSolver {

	final int threadCount;
	final CyclicBarrier barrier;
	final List<Integer> list;
	private long sum;
	private final static int MAIN_THREAD = 1;

	public CyclicBarrierSolver(int threadCount, List<Integer> list) {
		this.list = list;
		this.threadCount = threadCount;
		barrier = new CyclicBarrier(this.threadCount + MAIN_THREAD);
	}

	public long total() {
		int size = list.size();
		int mean = size / threadCount;

		ExecutorService executor = Executors.newFixedThreadPool(threadCount);
		for (int i = 0; i < threadCount; i++) {
			int fromIndex = mean * i;
			// int toIndex = i == threadCount - 1 ? size : mean * (i + 1);
			int toIndex = i == threadCount - 1 ? size : mean + fromIndex;

			executor.execute(new Worker(fromIndex, toIndex));
		}

		try {
			barrier.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}

		executor.shutdown();

		return sum;
	}

	class Worker implements Runnable {

		private int start;
		private int end;

		private Worker(int start, int end) {
			this.start = start;
			this.end = end;
		}

		public void run() {
			subtotal(start, end);

			try {
				barrier.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}

		public void subtotal(int start, int end) {
			long result = 0;
			for (int i = start; i < end; i++) {
				result += list.get(i);
			}

			synchronized (this) {
				sum += result;
			}
		}
	}
}
/*public class Solver {

	final int threadCount;
	final CyclicBarrier barrier;
	final List<Integer> list;
	private long sum;
	private final static int MAIN_THREAD = 1;

	public Solver(int threadCount, List<Integer> list) {
		this.threadCount = threadCount;
		this.list = list;
		barrier = new CyclicBarrier(threadCount + MAIN_THREAD);
	}

	public long total() {
		int size = list.size();
		int mean = size / threadCount;

		ExecutorService executor = Executors.newFixedThreadPool(threadCount);
		for (int i = 0; i < threadCount; ++i) {
			int fromIndex = mean * i;
			int toIndex = mean * (i + 1);
			if (i == threadCount - 1) {
				toIndex = size;
			}

			executor.execute(new Worker(list.subList(fromIndex, toIndex)));
		}

		try {
			barrier.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			e.printStackTrace();
		}

		executor.shutdown();

		return sum;
	}

	class Worker implements Runnable {

		private List<Integer> subList;

		private Worker(List<Integer> subList) {
			this.subList = subList;
		}

		public void run() {
			subtotal(subList);

			try {
				barrier.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}

		public void subtotal(List<Integer> list) {
			long result = 0;
			for (Integer item : list) {
				result += item;
			}

			synchronized (this) {
				sum += result;
			}
		}
	}
}*/

